/*
日志器模块：对日志等级，格式化，落地模块进行整合
    1. 同步日志器
    2. 异步日志器
*/
#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__
#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>
#include <unordered_map>

namespace log
{
    class SyncLogger;
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name, Formatter::ptr &formatter, std::vector<Sink::ptr> &sinks, Level::value &limit_level)
            : _logger_name(logger_name), _limit_level(limit_level), _formatter(formatter), _sinks(sinks) {}
        void debug(const std::string &filename, const size_t &line, const std::string &fmt, ...)
        {
            // 1. 获取不定参fmt
            va_list p;
            va_start(p, fmt);
            // 2.格式化
            serialize(Level::value::DEBUG, filename, line, fmt, p);
            va_end(p);
        }
        void info(const std::string &filename, const size_t &line, const std::string &fmt, ...)
        {
            // 1. 获取不定参fmt
            va_list p;
            va_start(p, fmt);
            // 2.格式化
            serialize(Level::value::INFO, filename, line, fmt, p);
            va_end(p);
        }
        void warn(const std::string &filename, const size_t &line, const std::string &fmt, ...)
        {
            // 1. 获取不定参fmt
            va_list p;
            va_start(p, fmt);
            // 2.格式化
            serialize(Level::value::WARN, filename, line, fmt, p);
            va_end(p);
        }
        void error(const std::string &filename, const size_t &line, const std::string &fmt, ...)
        {
            // 1. 获取不定参fmt
            va_list p;
            va_start(p, fmt);
            // 2.格式化
            serialize(Level::value::ERROR, filename, line, fmt, p);
            va_end(p);
        }
        void fatal(const std::string &filename, const size_t &line, const std::string &fmt, ...)
        {
            // 1. 获取不定参fmt
            va_list p;
            va_start(p, fmt);
            // 2.格式化
            serialize(Level::value::FATAL, filename, line, fmt, p);
            va_end(p);
        }
        const std::string &name() { return _logger_name; }

    protected:
        // 抽象接口，日志的落地输出，不同的日志器有不同的输出方式
        virtual void log(const char *data, size_t len) = 0;

        void serialize(const Level::value &level, const std::string &filename, const size_t &line, const std::string &fmt, va_list &p)
        {
            // 0. 获取不定参fmt
            char *tmp;
            if (-1 == vasprintf(&tmp, fmt.c_str(), p))
            {
                std::cout << "vasprintf()失败" << std::endl;
                return;
            }
            // 1. 判断是否大于限制等级
            if (level < _limit_level)
                return;
            // 2. 格式化msg消息
            LogMsg msg(level, filename, line, _logger_name, tmp);
            free(tmp);
            std::stringstream ss;
            std::string str = _formatter->format(msg);
            // 3. 日志落地
            log(str.c_str(), str.size());
        }

    protected:
        std::string _logger_name;               // 日志器名称
        std::atomic<Level::value> _limit_level; // 日志限制等级
        Formatter::ptr _formatter;              // 日志格式
        std::vector<Sink::ptr> _sinks;          // 落地方式（可能有多种落地方式）
        std::mutex _mutex;
    };
    // 同步日志器
    class SyncLogger : public Logger
    {
    public:
        using ptr = std::shared_ptr<SyncLogger>;
        SyncLogger(const std::string &name, Formatter::ptr formatter,
                   std::vector<Sink::ptr> &sinks, Level::value level = Level::value::DEBUG)
            : Logger(name, formatter, sinks, level)
        {
            std::cout << Level::toString(level) << " 同步日志器: " << name << "创建成功...\n";
        }

    protected:
        void log(const char *data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto &ptr : _sinks)
            {
                ptr->log(data, len);
            }
        }
    };
    // 异步日志器
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &name, Formatter::ptr formatter, std::vector<Sink::ptr> &sinks,
                    Level::value level = Level::value::DEBUG, AsyncType type = AsyncType::SAFE)
            : Logger(name, formatter, sinks, level),
              _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), type))
        {
        }
        void log(const char *data, size_t len) override // 将数据写入缓冲区
        {
            _looper->push(data, len);
        }
        void realLog(Buffer &buf) // 设计一个实际落地方式（将缓冲区的数据落地）
        {
            if (_sinks.empty())
                return;
            for (auto &ptr : _sinks)
            {
                ptr->log(buf.begin(), buf.readAbleSize());
            }
        }

    private:
        AsyncLooper::ptr _looper;
    };
    /*
        使用建造者模式，降低用户创建日志器的成本
        1. 抽象一个日志器建造者类
            1.1 通过日志器类型参数决定创建什么日志器
            1.2 完成日志器对象零部件的构建
            1.3 设置全局日志器建造者，局部日志器建造者
    */
    enum LoggerType
    {
        SYNC_LOGGER,
        ASYNC_LOGGER
    };
    class LoggerBuilder
    {
    public:
        // 默认为同步日志器，等级为debug
        LoggerBuilder()
            : _logger_type(LoggerType::SYNC_LOGGER),
              _limit_level(Level::value::DEBUG),
              _looper_type(AsyncType::SAFE) {}
        void buildLoggerType(const LoggerType &logger_type) { _logger_type = logger_type; }
        void buildLoggerName(const std::string &logger_name) { _logger_name = logger_name; }
        void buildLoggerLevel(const Level::value &level) { _limit_level = level; }
        void buildFormatter(const std::string &pattern = "")
        {
            if (pattern == "")
                _formatter = std::make_shared<Formatter>();
            else
                _formatter = std::make_shared<Formatter>(pattern);
        }
        template <class SinkType, class... Args>
        void buildSink(Args &&...args)
        {
            Sink::ptr sink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(sink);
        }
        void buildEnableUnSafeAsync() { _looper_type = AsyncType::UNSAFE; }
        virtual Logger::ptr build() = 0;

    protected:
        LoggerType _logger_type;       // 日志器类型
        std::string _logger_name;      // 日志器名称
        Level::value _limit_level;     // 日志限制等级
        Formatter::ptr _formatter;     // 日志格式
        std::vector<Sink::ptr> _sinks; // 落地方式（可能有多种落地方式）
        AsyncType _looper_type;        // 异步日志器类型
    };
    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty()); // 必须得有名称
            if (_formatter.get() == nullptr)
                _formatter = std::make_shared<Formatter>();
            if (_sinks.empty())
            {
                auto sink = SinkFactory::create<StdoutSink>();
                _sinks.push_back(sink);
            }
            if (_logger_type == LoggerType::SYNC_LOGGER)
            {
                return std::make_shared<SyncLogger>(_logger_name, _formatter, _sinks, _limit_level);
            }
            else
            {
                return std::make_shared<AsyncLogger>(_logger_name, _formatter, _sinks, _limit_level, _looper_type);
            }
        }
    };

    // 日志器管理器类  单例模式，用于创建全局日志器
    class LoggerManager
    {
    public:
        static LoggerManager &getInstance()
        {
            static LoggerManager eton;
            return eton;
        }
        void addLogger(Logger::ptr &logger)
        {
            if (hasLogger(logger->name()))
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(), logger));
        }
        bool hasLogger(const std::string &name) // 判断日志器是否重复
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it != _loggers.end())
                return true;
            else
                return false;
        }
        Logger::ptr getLogger(const std::string &name) //
        {
            auto it = _loggers.find(name);
            if (it != _loggers.end())
                return it->second;
            return Logger::ptr();
        }
        Logger::ptr defaultLogger() // 获取默认构造器
        {
            return _default_logger;
        }

    private:
        LoggerManager()
        {
            // 先构造一个日志器建造者
            std::unique_ptr<LoggerBuilder> builder(new LocalLoggerBuilder());
            builder->buildLoggerName("root"); // 默认日志器名称
            _default_logger = builder->build();
            _loggers.insert(std::make_pair("root", _default_logger));
        }

    private:
        std::mutex _mutex;
        Logger::ptr _default_logger;                           // 默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers; // 日志器集合
    };
    
    // 全局日志器建造者
    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty()); // 必须得有名称
            if (_formatter.get() == nullptr)
                _formatter = std::make_shared<Formatter>();
            if(_sinks.empty())
            {
                auto sink = SinkFactory::create<StdoutSink>();
                _sinks.push_back(sink);
            }
            Logger::ptr logger;
            if (_logger_type == LoggerType::SYNC_LOGGER)
            {
                logger = std::make_shared<SyncLogger>(_logger_name, _formatter, _sinks, _limit_level);
            }
            else
            {
                logger = std::make_shared<AsyncLogger>(_logger_name, _formatter, _sinks, _limit_level, _looper_type);
            }
            LoggerManager::getInstance().addLogger(logger);  // 构建全局构造器
            return logger;
        }
    };
}

#endif